- Article
- 2018-12-28

Не будем рассказывать о "вступлении" в программировании, о работе процессора, процесса компиляции и интерпретации ( or трансляции ) программы, а сразу попытаемся практично подойти к понятию программировании в Pawn
P.S
Если вы желаете больше влиться в мир программ, советую изучить следующие темы:
Ну что же, давайте разбирать простейший плагин написанный на Pawn для CS 1.6 ( я решил взять броню, ибо считаю здесь есть всё для простого описания )
#include <amxmodx>
#include <fakemeta>
#include <zombieplague>
#define MAX_IN_ROUND 4 // Максимум в раунде
const g_item_cost = 15 // Цена
new const g_sound_buyarmor[] = { "items/tr_kevlar.wav" } // присваиваем константе массиву значение ( строку ) путь до звука
const g_armor_amount = 250 // Покупка за 1 раз
const g_armor_limit = 250 // Лимит
new g_armor_counter[33] = 0 // все 32 значения массива ( счёт начинается с 0 ) будут при компиляции/старта плагина равны 0
new extra_armor[512] // объявление массива
new g_itemid_humanarmor // объявление переменной
public plugin_precache()
{
precache_sound(g_sound_buyarmor) // кэшируем звук покупки
}
public plugin_init()
{
register_plugin("[ZP] Extra-Item: Anti-Infection Armor", "1", "Dambas") // регистрируем плагин
register_event("ResetHUD","Start_round","be") // регистрируем событие смены худов CS
formatex(extra_armor, charsmax(extra_armor), "%L", LANG_SERVER, "EXTRA_ARMOR"); // в массив extra_armor засовываем значение из lang файла которое равно EXTRA_ARMOR
g_itemid_humanarmor = zp_register_extra_item(extra_armor , g_item_cost, ZP_TEAM_HUMAN) // присваиваем переменной возвращаемое значение функции
register_dictionary("zombie_plague.txt"); // регистрируем lang файл
}
public Start_round(id)
{
g_armor_counter[id] = 0 // обнуляем лимит покупок у всех игроков в начале раунда
}
public zp_extra_item_selected(id, itemid) // описываем "форвард" для нашего плагина
{
if (itemid == g_itemid_humanarmor) // проверка на то, что если мы выбрали предмет из нашего плагина
{
if (g_armor_counter[id] > MAX_IN_ROUND) // если лимит покупок у игрока не выше того, что мы указали в MAX_IN_ROUND продолжаем идти дальше
{
ColorChat(id, "!g[ZP] !yТы купил максимум брони!" ) // вызываем функцию которая отобразит сообщение игроку
return ZP_PLUGIN_HANDLED // прекращаем данную функцию + возвращаем деньги игроку
}
else
{
set_pev(id, pev_armorvalue, float(min(pev(id, pev_armorvalue)+g_armor_amount, g_armor_limit))
// Мы выберем минимальное ( min() ) значение из [b]значений броня игрока+количетсво покупаемой брони[/b] pev(id, pev_armorvalue)+g_armor_amount и [b]максимальное количество брони[/b]
[b] // То есть, у игрока не может быть брони больше, чем то, что мы указали в g_armor_limit[/b]
engfunc(EngFunc_EmitSound, id, CHAN_BODY, g_sound_buyarmor, 1.0, ATTN_NORM, 0, PITCH_NORM) // воспроизводим звук указанный в массиве g_sound_buyarmor
g_armor_counter[id]++ // уменьшаем для игрока [id] его лимит
ColorChat(id, "!g[ZP] !yТы купил !g250 брони!" ) // вызываем функцию для вывода сообщению игрока
}
}
return PLUGIN_HANDLED // заканчиваем работу функции
}
stock ColorChat(const id, const input[], any:...) // тут много сложного для новичков
{
new count = 1, players[32] // создаем переменную и массив для игроков
static msg[191] // создаём статичную переменную, чтобы её значение не удалялось после окончания функции
vformat(msg, 190, input, 3) // из массива с любым размером в массив msg с размером 191
replace_all(msg, 190, "!g", "^4") // меняем все !g на ^4
replace_all(msg, 190, "!y", "^1") // меняем все !y на ^1
replace_all(msg, 190, "!t", "^3") // меняем все !t на ^3
if (id) players[0] = id; else get_players(players, count, "ch") // если id не 0, то в в ячейку массива players[0] кидаем id игрока ( для будущего вывода сообщения именно ему ), ИНАЧЕ получаем id всех игроков для будущего вывода всем игрокам
{
for(new i = 0; i < count; i++) // цикл от 0 до количество игроков
{
if(is_user_connected(players[i])) // проверяем на коннект игрока ( антикраш )
{
message_begin(MSG_ONE_UNRELIABLE, get_user_msgid("SayText"), _, players[i]) // запускаем сообщение, с параметром вывода текста
write_byte(players[i]) // кому выводим
write_string(msg) // что выводим
message_end() // заканчиваем сообщение
}
}
}
}
В любой программе есть 3 блока:
Переменная.
В любой программе можно объявлять переменные. Они могут быть глобальными, и локальными. Разница в том, что к глобальным переменным можно обращаться из любой части кода, а к локальным только в том, где они объявлены.
Так же, у любой переменной, есть свои свойства, а именно:
- тип данных
- значение
- адрес
- имя
Чтобы при объявлении сразу присвоить значения, используется оператор "=": new ИмяПеременной = 10;
Чтобы принудительно задать тип переменной, нужно использовать структуру: new ТипДанных:ИмяПеременной.
Список возможных типов переменной:
- Integer - целочисленный
- Float - дробный ( пример: 0.045 )
- Bool - логический ( либо true, либо false ВАЖНО: Не 0, или 1 )
- Array - массив
P.S
Нельзя забывать про так называемые "инструкции". Через них тоже можно объявлять переменные которые можно использовать в коде. Они схожи с константами, но их основное отличие, что во время компиляции они лишь заменяют своё имя, на их значение в коде
Структура объявления: #define ИМЯ_ПЕРЕМЕННОЙ ЗНАЧЕНИЕ
#define MYNAME Player
Массивы.
Следующая структура, которую нужно понимать для программирования в Pawn. Массив, грубо говоря, строка из переменных, у которых есть свой адрес и значение.
Для объявления массива, используются структура: new ИмяМассива[РазмерМассива];
В любом языке программирования, так же можно объявить двумерный массив, это, опять же грубо говоря, таблица, в которой в каждой ячейке массива - хранится адрес другого массива. Общую структуру такого массива можно представить как таблицу
new TutMassiv[3][3];
for(new i=0; i < 3; i++)
for(new k=0; k < 3; i++)
TutMassiv[i][k] = i;
TutMassiv[0][0] =0 | TutMassiv[1][0] =0 | TutMassiv[2][0] =0 |
TutMassiv[0][1] =1 | TutMassiv[1][1] =1 | TutMassiv[2][1] =1 |
TutMassiv[0][2] =2 | TutMassiv[1][2] =2 | TutMassiv[2][2] =2 |
Чтобы задать значения массива сразу при объявлении, используется оператор "=" и фигурные скобки:
new tut[3] = { 5, 4, 10 }; - одномерный массив
new tutD[2][2] = { { 3, 2 }, { 4, 6 } }; - двумерный массив ( таблица )
new tutT[3][3][3] =
{
{
{1, 2, 3}, {4, 5, 6}, {7, 8, 9}
},
{
{1, 2, 3}, {4, 5, 6}, {7, 8, 9}
},
{
{1, 2, 3}, {4, 5, 6}, {7, 8, 9}
}
}; - трёхмерный массив ( пространство )
Функции.
Еще одна важнейшая часть для осознания Pawn'а. Функции нужны для того, чтобы не повторять много раз одни и те-же куски кода, а отделить их отдельным именем и вызывать при необходимости.
Например, вам нужно при убийстве игрока, давать ему броню, здоровье, уровень и еще много много бонусов. Чтобы не загрязнять код, лучше вызывать одну функцию в событии убийства.
Все функции в Pawn должны начинаться со слова public. Общая структура написания функций: public ИмяФункции(Атрибут, Атрибут2, Атрибут3, ..., АтрибутN) { описании функции )
Чтобы вызвать функцию, нужно просто написать её имя, и отослать туда какие либо данные - атрибуты. Имена атрибутов, могут не совпадать с именами переменных которые вы туда отправляете ( НО! Типы должны обязательно совпадать, так как вы не можете присвоить типу bool тип Integer, это вызовет Warning 213 при компиляции )
public NameFunction(id, Health, Armor) // Описание функции
{
set_user_health(id, Health);
set_user_armor(id, Armor);
}
// code
NameFunction(id, 300, 300); // Вызов функции
// code
Циклы.
Нужны для автоматического повтора каких либо действий при совпадении определенного условия.
Существует 3 вида циклов:
- for(идентификация счетчика; условие; инкремент ( прибавление значение счетчика ))
- while(условие)
- do{ реализация кода }while(условие)
break - останавливает выполнения цикла
continue - переходит на следующий шаг цикла
Как это работает
- Цикл For
for(new i=0; i < 5; i++) { Тело Цикла }
Сначала мы объявляем локальную переменную i и присваиваем ей значение 0. Эта локальная переменная будет использоваться только внутри тела цикла. Можно использовать и не локальные переменные написав её внутри for без оператора new и присваивания.
После инициализации счетчика, мы проверяем условие. Если i < 5, начинаем выполнять операции находящиеся внутри тела цикла. После последней операции цикла, мы добавляем к существующему значению i единицу ( т.е. i = i + 1 ). Это и описано в инкременте счетчика(..; i++)
После чего снова идёт условие. - Цикл while(i<5) { Тело Цикла }
Здесь всё так же, только нам придётся внутри тела цикла самому увеличивать значение i. Цикл будет работать, пока условие в скобках после while будет выполняться - Цикл do{ Тело Цикла }while(условие)
Этот цикл, отличается от других тем, что сначала мы выполняем операции в теле цикла, а только потом проверяем условия, и если оно верно, то снова выполняем операции до момента пока условие не сработает.
Операция Ветвления - if(){} else if(){} else{}
Операции ветвления, или условные операции, самое частое и нужное в программировании. Они нужны для проверки какого либо условия и дальнейшего выполнения или изменения условия.
Обязательная структура:
if(условие) // ЕСЛИ ...
{
Операции
}
else if(условие) // ИНАЧЕ ЕСЛИ...
{
}
..... // здесь может быть сколько угодно структур else if(условие)
else if(условие)
{
Операции
}
else // ИНАЧЕ .... - выполняется, если не одно из else if не выполнилось
{
Операции
}
Если не одна операция ветвления не совпала с условием, и операции else нету, то ВСЯ операция ветвления просто игнорируется и код идёт дальше Функция public plugin_init(), и посмотрим, что делает каждая строчка
public plugin_init() // Функция которая вызывается при компиляции плагина или запуска сервера
{
register_plugin("[ZP] Extra-Item: Anti-Infection Armor", "1", "Dambas") // Регистрация плагина, и присваивание ему имени
register_event("ResetHUD","Start_round","be") // Регистрация события, и присваивания ему в данном плагине функции ( в данном случае ResetHUD )
formatex(extra_armor, charsmax(extra_armor), "%L", LANG_SERVER, "EXTRA_ARMOR"); // formatex - функция работы со строкой, далее мы рассмотрим её поближе
g_itemid_humanarmor = zp_register_extra_item(extra_armor , g_item_cost, ZP_TEAM_HUMAN) // Переменная как значение функции. Далее мы рассмотрим зачем это нужно
register_dictionary("zombie_plague.txt"); // Подключение lang-файла для русификации плагина
}
Я собрал все нужные для новичка события для создания функций их реализации:
- register_event - регистрирует некоторые из стандартных событий Half-Life. Полный список тут - События Half-Life
- register_logevent - регистрирует события которые обычно пишутся в логах. Нам нужны чаще всего для начала и конца раунда
- RegisterHam - не побоюсь для новичков сказать, что это нужно для того, чтобы отловить какое то событие. Но функционал намного выше. Нам чаще всего нужно для событий получение урона, смерти, спавна и других. Удобность - наличие id игрока
- register_touch - если углубитесь в тему Pawn'а, то эта функция поможет вам отловить событие касание объектов друг об друга
Функция plugin_precache(), нужна для кэширования ваших ресурсов ( модели, звуки, спрайты ) на сервере и в дальнейшем для передачи их игроку.
Внутри данной функции можно использовать несколько функций кэширования ( разных библиотек )
Fakemeta: engfunc(имя константы fakemeta, имя кэшируемой переменной)
- Константа EngFunc_PrecacheModel - для кэширования модели или спрайта. Пример: engfunc(EngFunc_PrecacheModel, Model)
- Константа EngFunc_PrecacheSound - для кэширования звука. Пример engfunc(EngFunc_PrecacheSound, Sound)
- precache_model
- precache_sound
FAQ: ( ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ НОВИЧКОВ )
- С чего начать писать плагин, на что смотреть, что делать если я не понимаю как работает код
&Я не понимаю как работает код&
Для начала, посмотрите на название переменных и событиях описанных в public plugin_init()
Поймите структуру программы, какие функции вызываются первыми, какие используются чаще, какие важные. По смыслу вы сможете понять, в каком месте кода вы должны искать.
Например: Вопрос: Мне нужно в определенном плагине, изменить радиус взрыва ракеты.
Для начала, мне нужно найти функцию, которая отвечает зазапуск самой ракеты. Потом найти, функцию которая отвечает за взрыв ракеты. После чего найти структуру message_begin, ведь скорее всего именно в ней указывается радиус взрыва
&С чего начать писать плагин&
Продумайте в голове все свои мысли. Изобразите структуру вашего плагина на листочке или в Paint ( если вы собрались браться за что то большое ). Потом обдумайте, какие библиотеки ваш лучше использовать. Если вы намереваетесь писать плагин связанный как либо внутри-игровыми объектами: задумайтесь что будет лучше, использовать модуль engine или fakemeta (изучите их для начала). Подумайте, как будут использоваться переменные, какие функции вы распишите, какие события затронете.
- Чем отличается (id) от [id]
Всё, что находится в круглых скобках - это вызов функции. Квадратные скобки - обращение к ячейки массива с идентификатором указанным внутри []
То есть, set_user_health(id, Health) -> мы отправляем в функции число которое постоянно хранится в id
А users[id] -> мы обращаемся к массиву users по номеру который записан в id
Ни в коем случае не путайте!
- Как исправлять Warning'и
Начнем с того, что ошибки(error) и предупреждения(warning) - это разные вещи. Если в вашем плагине ошибка - он не скомпилируется. Если предупреждения - скомпилируются, но компилятор вас предупредит, что в каком то месте допущена синтаксическая ошибка, которая может фатально или не очень повлиять на работу сервера.
Всё зависит от самого Warning'а. Обычно, переведя его содержания и посмотрев на строчку которая его вызвала - вы сами всё поймете.
Но не со следующими:
Warning 217, Warning 213 - иногда новички конкретно зависают над этими предупреждениями.
Ну что же, давайте рассмотрим возможные варианты их появления - %Warning 213%
Тут может быть несколько вариантов. Чаще всего, предупреждение о не соответствии тэгов появляется когда функция принимает переменную одного типа, а вы отправляете другой
К примеру. Когда вы работаете с уроном, вы должны понимать, что любой урон в игре имеет тип Float. Поэтому работая с ним, вы либо при вызове функций должны сами присваивать ему тип Float, либо везде держать его в дробном состоянии
Нашел хороший пример:
set_pev(iPlayer, pev_velocity, Float:{0.0,0.0,0.0})
В данной функции при её вызове, вы сами должны указать тип Float, чтобы не столкнуться с проблемой 213 предупреждения. - &Warning 217&
Тут 2 варианта. Либо у вас не выровнены отступы ( где то Табулирование, где то лишние пробелы ), либо неправильная структура кода
К неправильной структуре я отношу забытые фигурные скобки
Запомните, в функциях ветвления и циклах, не использовать фигурные скобки можно только в ситуации, когда в теле цикла или ветвления используется только одна операция, то есть// Правильно if(X>5) a = 3; else a = 5;; // Неправильно if(X>5) a = 3; b = 6; else a = 5;
%25
Discount on all purchases
builds until September 16, 2024
Especially for you - Гость

Buy an assembly

Готовый сервер «CSDM Legendary + Пушки Лазеры» для CS 1.6
yes of course , try it , and let me know if it doesnt work

Готовый сервер «CSDM Legendary + Пушки Лазеры» для CS 1.6
Worksforamxmod1.9?

[CS 1.6] Knife - Vfx Kuronami Kunai
no problem, enjoy

[CS 1.6] Knife - Vfx Kuronami Kunai
thank bro you so good animation

[ZP] Как сделать модель рук зомби с гранатой через мод?
this is nicve
ReHLDS (Reverse-engineered) - this is a new step forward that gives a second wind to our servers. ReHLDS works 2 times faster than HLDS.
AMXModX is a Metamod add-on that allows you to create new modifications for Half-Life in the Pawn language
Reunion is a continuation of Dproto for ReHLDS. This is a metamod plugin that allows you to log into the 47/48 Non-Steam server.
Revoice is a Metamod plugin that allows voice chat between non-steam and steam clients.
The new Metamod-r contains a huge number of performance optimizations and much cleaner code. The kernel was written using a JIT compiler.
Ultimate Unprecacher is a plugin for MetaMod, it works on the principle of disabling unnecessary resources on your server, thereby you can free up space for resources for your plugins, using this module you can get rid of error 512!
ReAuthCheck - this is a Metamod plugin that checks your players for validity, with this module for REHLDS you can protect your server from bots that constantly spam ads or simply clog up a slot on the server!
NetBufExtender or NBEX - This is a metamod plugin that expands the пїЅInternet bufferпїЅ: server and client buffers (not 100% guaranteed). Expands up to 64 kb. This means that players are less likely to be kicked with the error "Reliable channel overflowed"".
UINO пїЅ metamod plugin that allows you to remove unnecessary fields from userinfo(setinfo) when the engine passes it to other players on the server. This measure reduces the amount of data transferred and slightly reduces the chance of being kicked with "Reliable channel overflowed".